package top.malaoshi.data;

import java.util.*;

public class GroupBy {

    protected DataTable dataTable;
    protected String[] groupByColumns;
    public GroupBy(DataTable dataTable){
        this.dataTable = dataTable;
    }

    public GroupBy groupBy(String ... columns) {
        this.groupByColumns = columns;
        return this;
    }
    public GroupByAgg count(){
        return new GroupByAgg(dataTable,groupByColumns, getResult()).count();
    }
    public GroupByAgg max(String column){
        if(column == null || "".equals(column)){
            throw new IllegalArgumentException("max()函数需要传入列名");
        }
        return new GroupByAgg(dataTable,groupByColumns, getResult()).max(column);
    }
    public GroupByAgg min(String column){
        if(column == null || "".equals(column)){
            throw new IllegalArgumentException("min()函数需要传入列名");
        }
        return new GroupByAgg(dataTable,groupByColumns, getResult()).min(column);
    }
    public GroupByAgg avg(String column){
        if(column == null || "".equals(column)){
            throw new IllegalArgumentException("avg()函数需要传入列名");
        }
        return new GroupByAgg(dataTable,groupByColumns, getResult()).avg(column);
    }
    public GroupByAgg sum(String column){
        if(column == null || "".equals(column)){
            throw new IllegalArgumentException("sum()函数需要传入列名");
        }
        return new GroupByAgg(dataTable,groupByColumns, getResult()).sum(column);
    }

    public List<Result> getResult() {
        /*
        key：String，分组列，如果是多个由 “,”分割
        value：List，DataRow
         */
        Map<String, Result> map = new LinkedHashMap<>();

        for(int i = 0,count = dataTable.rows().count() ; i<count;i++){

            DataRow dataRow = dataTable.rows().get(i);


            // 拼接key
            String key = "";
            for(String column : groupByColumns){
                Object value = dataRow.getValue(column);
                key += value+",";
            }
            if(map.containsKey(key)){
                Result result = map.get(key);

                result.addValue(dataRow);
            }else{
                Result result = new Result();

                for(String column : groupByColumns){
                    Object value = dataRow.getValue(column);
                    result.addColumn(value);
                }


                result.addValue(dataRow);
                map.put(key,result);
            }
        }

        List<Result> reList = new ArrayList<>();
        for(Map.Entry<String, Result> entry : map.entrySet()){
            reList.add(entry.getValue());
        }
        // 对key进行排序
        reList.sort(new ComparatorImpl(dataTable, groupByColumns,0));

        return reList;

    }


    public class ComparatorImpl implements Comparator<Result>{
        private DataTable dataTable;
        private String[] columns;
        private int index = 0;
        ComparatorImpl(DataTable dataTable,String[] columns,int index){
            this.dataTable = dataTable;
            this.columns = columns;
            this.index = index;
        }
        @Override
        public int compare(Result r1, Result r2) {
            int i = index;

            String column = columns[i];
            DataColumn dataColumn = dataTable.columns().get(column);
            if(dataColumn.getType() == DataColumn.Type.INT ){
                Integer o1 = (Integer) r1.getColumns().get(i);
                Integer o2 = (Integer) r2.getColumns().get(i);

                if(o1==null && o2!=null){
                    return -1;
                }else if(o1!=null && o2==null){
                    return 1;
                }else if(o1==null && o2==null){
                    return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
//                        return 0;
                }else {
                    int res = o1 - o2;
                    if(res == 0){
                        return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
                    }else{
                        return res;
                    }
                }

            }else if(dataColumn.getType() == DataColumn.Type.DOUBLE){
                Double o1 = (Double) r1.getColumns().get(i);
                Double o2 = (Double) r2.getColumns().get(i);

                if(o1==null && o2!=null){
                    return -1;
                }else if(o1!=null && o2==null){
                    return 1;
                }else if(o1==null && o2==null){
                    return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
//                        return 0;
                }else {
                    if(o1 < o2) {
                        return -1;
                    }else if(o1 == o2){
                        return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
//                            return 0;
                    }else{
                        return 1;
                    }
                }

            }else if(dataColumn.getType() == DataColumn.Type.TEXT){
                String o1 = (String) r1.getColumns().get(i);
                String o2 = (String) r2.getColumns().get(i);

                if(o1==null && o2!=null){
                    return -1;
                }else if(o1!=null && o2==null){
                    return 1;
                }else if(o1==null && o2==null){
//                        return 0;
                    return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
                }else {
                    int res = o1.compareTo(o2);

                    if(res == 0){
                        return new ComparatorImpl(dataTable,columns,index+1).compare(r1,r2);
                    }else{
                        return res;
                    }
                }

            }else{
                throw new DataColumnTypeNotSupportedException(column,dataColumn.getType(),"不支持此操作！");
            }


        }
    }

    /**
     * groupby 结果
     */
    public class Result {
        private List<Object> columns = new ArrayList<>();
        private List<DataRow> dataRows = new ArrayList<>();

        public void addColumn(Object key){
            columns.add(key);
        }
        public void addValue(DataRow dataRow){
            dataRows.add(dataRow);
        }
        public List<Object> getColumns(){
            return columns;
        }
        public List<DataRow> getDataRows(){
            return dataRows;
        }
    }


}
